﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using BlogML.Xml;
using WeBlog.Interfaces;
using WeBlog.Repositories;
using WeBlog.Models;

namespace WeBlog.Services.BlogML
{
    /// <summary>
    /// Imports BlogML xml file format
    /// </summary>
    public class BlogMLImporter
    {
        private readonly IUnitOfWork _unitOfWork;
        private readonly PostRepository _postRepository;
        private readonly CategoryRepository _categoryRepository;
        private readonly UserRepository _userRepository;

        private BlogMLBlog _blog;

        private List<Category> _categoryList;

        public BlogMLImporter(IUnitOfWork unitOfWork)
        {
            _unitOfWork = unitOfWork;
            _postRepository = new PostRepository(unitOfWork);
            _categoryRepository = new CategoryRepository(unitOfWork);
            _userRepository = new UserRepository(unitOfWork);
            _categoryList = new List<Category>();
        }


        /// <summary>
        /// Main method which make import
        /// </summary>
        /// <param name="inputStream">Stream which represent xml file</param>
        /// <param name="userId">Current user Id</param>
        public void ImportBlog(Stream inputStream, int userId)
        {

            _blog = BlogMLSerializer.Deserialize(inputStream);

            ImportCategories(_blog);
            ImportPosts(_blog, userId);

        }

        /// <summary>
        /// Imports categories
        /// </summary>
        /// <param name="blog">Represents deserialized xml file with blog data</param>
        private void ImportCategories(BlogMLBlog blog)
        {

            foreach (var category in blog.Categories)
            {
                var cat = new Category
							  {
							     Description = string.IsNullOrEmpty(category.Description) ? "" : category.Description,
								 DateCreated = category.DateCreated,
								 DateModified = category.DateModified
							  };

                cat.Name = String.IsNullOrEmpty(category.Title) ? "default" : category.Title;

                cat.CategoryId = Convert.ToInt32(category.ID);

                if (!string.IsNullOrEmpty(category.ParentRef) && category.ParentRef != "0")
                    cat.ParentId = Convert.ToInt32(category.ParentRef);

                if (!_categoryRepository.FindAll().Any(x => x.Name == cat.Name))
                {
                    _categoryRepository.Add(cat);
                }

                _categoryList.Add(cat);
            }
        }

        /// <summary>
        /// Imports posts and relative to posts info
        /// </summary>
        /// <param name="blog">Represents deserialized xml file with blog data</param>
        /// <param name="userId">Current user Id</param>
        private void ImportPosts(BlogMLBlog blog, int userId)
        {

            foreach (var post in blog.Posts)
            {
                var p = new Post
							{
								Title = post.Title,
								DateCreated = post.DateCreated,
								LastModified = post.DateModified,
								Content = post.Content.Text,
								Published = post.Approved,
								PublishDate = post.DateCreated,
								Author = _userRepository.Find(userId),
								AreCommentsEnabled = true,
								Categories = new List<Category>()
							};

                string slug = String.Concat("/", Utils.RemoveIllegalCharacters(post.Title));
                Match slugMatch = Regex.Match(slug, @"/([^/\.]+)(?:$|\.[\w]{1,10}$)", RegexOptions.IgnoreCase);

                if (slugMatch.Success)
                    p.Slug = slugMatch.Groups[1].Value.Trim();

                if (post.Categories != null && post.Categories.Count > 0)
                {

                    for (int i = post.Categories.Count - 1; i >= 0; i--)
                    {
                        int catId = Convert.ToInt32(post.Categories[i].Ref);
                        var category = _categoryList.Where(x => x.CategoryId == catId).First();

                        if (!_categoryRepository.FindAll().Any(x => x.Name == category.Name))
                        {
                            p.Categories.Add(category);
                        }
                        else
                        {
                            var categoryFromRepository = _categoryRepository.FindByName(category.Name);
                            p.Categories.Add(categoryFromRepository);
                        }
                    }
                }

                p.PostComments = new List<PostComment>();

                if (post.Comments != null && post.Comments.Count > 0)
                {
                    for (int i = post.Comments.Count - 1; i >= 0; i--)
                    {
                        var comment = new PostComment()
										  {
											 Content = post.Comments[i].Content.Text,
											 DateTime = post.Comments[i].DateCreated,
											 Website = post.Comments[i].UserUrl,
											 Author = post.Comments[i].UserName
										  };
                        comment.Email = String.IsNullOrEmpty(post.Comments[i].UserEMail) ? "test@test.com" : post.Comments[i].UserEMail;
                        comment.CommentStatus = 2;
                        if (comment.CommentStatus == 2) p.ApprovedComments.ToList().Add(comment);
                        p.PostComments.Add(comment);

                    }
                }
                if (!_postRepository.FindAll().Any(x => x.Title == p.Title))
                    _postRepository.Add(p);
            }
            _unitOfWork.Commit();
        }
    }
}
